package com.gmrz.uaf.crypto.KeyAttestation;

import com.gmrz.util.Convert;
import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.X509CertificateStructure;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.*;
import java.security.cert.Certificate;
import java.security.interfaces.RSAPublicKey;
import java.util.Arrays;

/**
 * Created by zhangchao on 2018/6/13.
 */

public class KeyAttestationBcUtil {
    private static final Logger LOG = LogManager
            .getLogger(KeyAttestationBcUtil.class);

    private static final String TAG = "KeyAttestationBcUtil";

    public static final String KEY_DESCRIPTION_OID = "1.3.6.1.4.1.11129.2.1.17";


    /**
     *
     * verify fido android 7 attestation cerify result , now only support ecc
     *
     * @param certificates: data got by fido uafresponse exts , id is fido.uaf.android.key_attestation
     * @param rootCerts: data got by fido metadata exts, id is supportedExtensions -> fido.uaf.android.key_attestation
     * @param fc: finalchallenge hash , got by fido uafresponse
     * @param pubkey: pubkey for user , got by fido uafresponse
     *
     * @return reuslt for verify
     */
    public static final boolean verify(X509Certificate[] certificates, X509Certificate[] rootCerts, byte[] fc, byte[] pubkey, boolean isNeedAttestationTee){
        LOG.info(TAG,"verify");
        boolean result = false;
        try {
            //verify certification chain with certificates from phone and root certificates from metadata
            if (!verifyCertificateChain(certificates, rootCerts)) {
                LOG.info(TAG,"verify failed by cert chain");
                result = false;
                return result;
            }
            //verify pubkey with key from certificate and fido assertation
            if (!verifyPubkey(certificates,pubkey)){
                LOG.info(TAG,"verify failed by pubkey");
                result = false;
                return result;
            }
            //verify attestation key information with specific values
            if (!verifySecure(certificates, fc, isNeedAttestationTee)) {
                LOG.info(TAG,"verify failed by secure");
                result = false;
                return result;
            }
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
            LOG.info(TAG,"verify failed :" + e.getMessage());
        }
        return result;
    }

    public static final boolean verifyRSA(X509Certificate[] certificates, X509Certificate[] rootCerts, byte[] fc, PublicKey pubkey, boolean isNeedAttestationTee){
        LOG.info(TAG,"verify");
        boolean result = false;
        try {
            //verify certification chain with certificates from phone and root certificates from metadata
            if (!verifyCertificateChain(certificates, rootCerts)) {
                LOG.info(TAG,"verify failed by cert chain");
                result = false;
                return result;
            }
            //verify pubkey with key from certificate and fido assertation
//            if (!verifyPubkey(certificates,pubkey)){
//                LOG.info(TAG,"verify failed by pubkey");
//                result = false;
//                return result;
//            }
            //verify attestation key information with specific values
            if (!verifySecure(certificates, fc, isNeedAttestationTee)) {
                LOG.info(TAG,"verify failed by secure");
                result = false;
                return result;
            }
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
            LOG.info(TAG,"verify failed :" + e.getMessage());
        }
        return result;
    }


    private static KeyDescription parseCert(X509Certificate cert) throws Exception{
        if(cert == null){
            throw new IllegalArgumentException("cert is not null");
        }
        ASN1Sequence extensionData = extractAttestationSequence(cert);

        KeyDescription description = new KeyDescription();
        int attestationVersion = ASN1Util.getIntegerFromAsn1(extensionData.getObjectAt(KeyDescription.ATTESTATION_VERSION_INDEX));
        description.setAttestationVersion(attestationVersion);
        int attestationSecurityLevel = ASN1Util.getIntegerFromAsn1(extensionData.getObjectAt(KeyDescription.ATTESTATION_SECURITY_LEVEL_INDEX));
        description.setAttestationSecurityLevel(attestationSecurityLevel);
        int keymasterSecurityLevel = ASN1Util.getIntegerFromAsn1(extensionData.getObjectAt(KeyDescription.KEYMASTER_SECURITY_LEVEL_INDEX));
        description.setKeymasterSecurityLevel(keymasterSecurityLevel);
        byte[] attestationChallenge = ((ASN1OctetString) extensionData.getObjectAt(KeyDescription.ATTESTATION_CHALLENGE_INDEX)).getOctets();
        description.setAttestationChallenge(attestationChallenge);

        AuthorizationList teeEnforcedList = new AuthorizationList();
        ASN1Encodable[] teeEnforced = ((ASN1Sequence) extensionData.getObjectAt(KeyDescription.TEE_ENFORCED_INDEX)).toArray();
        int[] purpose = ASN1Util.getIntegerSetFromAsn1((ASN1Set) findAuthorizationListEntry(teeEnforced, AuthorizationList.KM_TAG_PURPOSE));
        teeEnforcedList.setPurpose(purpose);
        int keySize = ASN1Util.getIntegerFromAsn1(findAuthorizationListEntry(teeEnforced, AuthorizationList.KM_TAG_KEY_SIZE));
        teeEnforcedList.setKeySize(keySize);
        int algorithm = ASN1Util.getIntegerFromAsn1(findAuthorizationListEntry(teeEnforced, AuthorizationList.KM_TAG_ALGORITHM));
        teeEnforcedList.setAlgorithm(algorithm);
        boolean noAuthRequired = (null != findAuthorizationListEntry(teeEnforced, AuthorizationList.KM_TAG_NO_AUTH_REQUIRED));
        teeEnforcedList.setNoAuthRequired(noAuthRequired);
        int authType = ASN1Util.getIntegerFromAsn1(findAuthorizationListEntry(teeEnforced,AuthorizationList.KM_TAG_USER_AUTH_TYPE));
        teeEnforcedList.setUserAuthType(authType);
        byte[] applicationId = ASN1Util.getBytesFromAsn1(findAuthorizationListEntry(teeEnforced,AuthorizationList.KM_TAG_APPLICATION_ID));
        teeEnforcedList.setApplicationId(applicationId);
        int origin = ASN1Util.getIntegerFromAsn1(findAuthorizationListEntry(teeEnforced,AuthorizationList.KM_TAG_ORIGIN));
        teeEnforcedList.setOrigin(origin);
        boolean allApplication = (null != findAuthorizationListEntry(teeEnforced, AuthorizationList.KM_TAG_ALL_APPLICATIONS));
        teeEnforcedList.setAllApplications(allApplication);
        boolean rollBack = (null != findAuthorizationListEntry(teeEnforced,AuthorizationList.KM_TAG_ROLLBACK_RESISTANT));
        teeEnforcedList.setRollbackResitant(rollBack);

        ASN1Sequence rootOfTurst = (ASN1Sequence) findAuthorizationListEntry(teeEnforced,AuthorizationList.KM_TAG_ROOT_OF_TRUST);
        if(rootOfTurst != null){
            RootOfTrust trust = new RootOfTrust();
            byte[] verifiedBootKey =  ASN1Util.getBytesFromAsn1(rootOfTurst.getObjectAt(RootOfTrust.VERIFIED_BOOT_KEY_INDEX));
            trust.setVerifiedBootKey(verifiedBootKey);
            int verifiedBootState = ASN1Util.getIntegerFromAsn1(rootOfTurst.getObjectAt(RootOfTrust.VERIFIED_BOOT_STATE_INDEX));
            trust.setVerifiedBootState(verifiedBootState);
            boolean DeviceLocked = ASN1Util.getBooleanFromAsn1(rootOfTurst.getObjectAt(RootOfTrust.DEVICE_LOCKED_INDEX));
            trust.setDeviceLocked(DeviceLocked);
            teeEnforcedList.setRootOfTrust(trust);
        }

        int osVersion = ASN1Util.getIntegerFromAsn1(findAuthorizationListEntry(teeEnforced,AuthorizationList.KM_TAG_OS_VERSION));
        teeEnforcedList.setOsVersion(osVersion);
        int osPatchLevel = ASN1Util.getIntegerFromAsn1(findAuthorizationListEntry(teeEnforced,AuthorizationList.KM_TAG_PATCH_LEVEL));
        teeEnforcedList.setOsPatchLevel(osPatchLevel);
        int attestationChallenge2 = ASN1Util.getIntegerFromAsn1(findAuthorizationListEntry(teeEnforced,AuthorizationList.KM_TAG_ATTESTATION_CHALLENGE));
        teeEnforcedList.setAttestationChallenge(attestationChallenge2);
        byte[] attestationAppId = ASN1Util.getBytesFromAsn1(findAuthorizationListEntry(teeEnforced,AuthorizationList.KM_TAG_ATTESTATION_APPLICATION_ID));
        teeEnforcedList.setAttestationApplicationId(attestationAppId);

        description.setTeeEnforced(teeEnforcedList);
        return description;
    }

    private static ASN1Primitive findAuthorizationListEntry(ASN1Encodable[] authorizationList, int tag) {
        for (ASN1Encodable entry : authorizationList) {
            ASN1TaggedObject taggedEntry = (ASN1TaggedObject) entry;
            if (taggedEntry.getTagNo() == tag) {
                return taggedEntry.getObject();
            }
        }
        return null;
    }


    private static ASN1Sequence extractAttestationSequence(X509Certificate attestationCert) throws Exception {
        byte[] attestationExtensionBytes = attestationCert.getExtensionValue(KEY_DESCRIPTION_OID);
        LOG.info(TAG,"attestationExtensionBytes:"+ASN1Util.byte2hex(attestationExtensionBytes));
        if (attestationExtensionBytes == null || attestationExtensionBytes.length == 0) {
            throw new Exception("Couldn't find the keystore attestation " + "extension data.");
        }

        ASN1Sequence decodedSequence;
        ASN1InputStream asn1InputStream = null;
        try {
            asn1InputStream = new ASN1InputStream(attestationExtensionBytes);
            // The extension contains one object, a sequence, in the
            // Distinguished Encoding Rules (DER)-encoded form. Get the DER
            // bytes.
            byte[] derSequenceBytes = ((ASN1OctetString) asn1InputStream.readObject()).getOctets();
            // Decode the bytes as an ASN1 sequence object.
            ASN1InputStream seqInputStream = null;
            try {
                seqInputStream = new ASN1InputStream(derSequenceBytes);
                decodedSequence = (ASN1Sequence) seqInputStream.readObject();
            }finally {
                if(null != seqInputStream){
                    seqInputStream.close();
                }
            }
        }finally {
            if(null != asn1InputStream){
                asn1InputStream.close();
            }
        }
        return decodedSequence;
    }

    /**
     * 此方法是为了解决手机 attestation key 兼容性问题的
     * 手机端有个 ASM 的东西，这个东西是手机出场时内置在手机中的
     * 但是有些老旧手机中是没有 ASM 这个东西的，所以就使用 google 的这个标准进行支持，
     * 但是老旧手机中又有一些类型没有按照 google 的标准，所以就在此方法中注释掉一些校验，使其能够兼容
     * @param certificates
     * @param challenge
     * @param attestationTee
     * @return
     * @throws Exception
     */
    private static boolean verifySecure(X509Certificate[] certificates, byte[] challenge, boolean attestationTee) throws Exception{
        KeyDescription description = parseCert(certificates[0]);
        //key generate challenge
        if(!Arrays.equals(challenge,description.getAttestationChallenge())){
            LOG.info(TAG,"key is not fit challenge");
            return false;
        }
        //attestation security
//        if(attestationTee){
//            if(description.getAttestationSecurityLevel() != SecurityLevel.TrustedEnvironment){
//                LOG.info(TAG,"key is not tee");
//                return false;
//            }
//        }
//        //key security
//        if(description.getKeymasterSecurityLevel() != SecurityLevel.TrustedEnvironment){
//            LOG.info(TAG,"key is not tee");
//            return false;
//        }
//        AuthorizationList list = description.getTeeEnforced();
        //key purpose
//        if(list.getPurpose()!=null && list.getPurpose().length == 1){
//            int index = Arrays.binarySearch(list.getPurpose(),2);
//            if(index >= 1 || index <= -1){
//                LOG.info(TAG,"purpose is not sign");
//                return false;
//            }
//        }else{
//            LOG.info(TAG,"purpose is not sign");
//            return false;
//        }
        //key authtype
//        if(list.getUserAuthType() <= 0){
//            LOG.info(TAG,"user authtype is not fit");
//            return false;
//        }
        //key authTimeout
//        if(list.getAuthTimeout() != 0){
//            LOG.info(TAG,"user auth timeout is not 0");
//            return false;
//        }
        //key user required
//        if(list.isNoAuthRequired()){
//            LOG.info(TAG,"user auth required is not true");
//            return false;
//        }
//        //key all application
//        if(list.isAllApplications()){
//            LOG.info(TAG,"all applications is not granted");
//            return false;
//        }
//        //key origin
//        if(list.getOrigin() != 0){
//            LOG.info(TAG,"key is need generate");
//            return false;
//        }
        return true;
    }

    private static boolean verifyCertificateChain(X509Certificate[] certs,X509Certificate[] rootCerts) {
        boolean result = false;
        try{
            for (int i = 1; i < certs.length; ++i) {
                certs[i].checkValidity();
                if (i > 0) {
                    PublicKey pubKey = certs[i].getPublicKey();
                    certs[i - 1].verify(pubKey);
                    if (i == certs.length - 1) {
                        certs[i].verify(pubKey);
                    }
                }
            }

            X509Certificate last = certs[certs.length - 1];
            for(int i=0;i<rootCerts.length;i++){
                X509Certificate tmp = rootCerts[i];
                if(Arrays.equals(last.getPublicKey().getEncoded(),tmp.getPublicKey().getEncoded())){
                    result = true;
                    return result;
                }
            }
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (NoSuchProviderException e) {
            e.printStackTrace();
        } catch (SignatureException e) {
            e.printStackTrace();
        }
        return result;
    }

    private static byte[] getRawData(byte[] derData) {
        byte[] extractedData = new byte[32];
        Arrays.fill(extractedData, (byte) 0);
        if (derData.length > 32) {
            System.arraycopy(derData, 1, extractedData, 0, extractedData.length);
        } else {
            System.arraycopy(derData, 0, extractedData, extractedData.length - derData.length, derData.length);
        }
        return extractedData;
    }

    private static boolean verifyPubkey(X509Certificate[] certificates,byte[] pubkey) throws IllegalArgumentException, CertificateEncodingException {
        byte[] pk = new byte[65];
        byte[] Certpk = new byte[64];
        Byte flag =0x04;
        pk[0]=flag;
        Certpk=getPublicKey(certificates[0].getEncoded());
        System.arraycopy(Certpk,0,pk,1,Certpk.length);
        return Arrays.equals(pk,pubkey);//Arrays.equals(out.array(), pubkey);
    }

    //获取公钥
    public static byte[] getPublicKey(byte[] certByte){
        InputStream inStream = new ByteArrayInputStream(certByte);
        ASN1Sequence seq = null;
        ASN1InputStream aIn;
        byte[] pk = null;
        try{
            aIn = new ASN1InputStream(inStream);
            seq = (ASN1Sequence)aIn.readObject();
            X509CertificateStructure cert = new X509CertificateStructure(seq);
            SubjectPublicKeyInfo subjectPublicKeyInfo = cert.getSubjectPublicKeyInfo();
            DERBitString publicKeyData = subjectPublicKeyInfo.getPublicKeyData();
            byte[] publicKey = publicKeyData.getEncoded();
            byte[] encodedPublicKey = publicKey;
            pk = new byte[64];
            System.arraycopy(encodedPublicKey, 4, pk, 0, pk.length);

        }catch (IOException ioe){
            LOG.error("Failed to PublicKey the Root certificate.");
            throw new IllegalArgumentException("Failed to PublicKey the Root certificate.");
        }finally {
            LOG.debug("Certificate PublicKey:" + Convert.toHex(pk));
            return pk;
        }
    }

    public static byte[] decode(PublicKey key) {
        if (key instanceof RSAPublicKey){
            RSAPublicKey rsaPublicKey = (RSAPublicKey)key;
            BigInteger n = rsaPublicKey.getModulus();
            byte[] nba = n.toByteArray();
            BigInteger e = rsaPublicKey.getPublicExponent();
            byte[] eba = e.toByteArray();

            byte[] publicKeyEncoded = new byte[256 + eba.length];

            if ((nba.length > 257) || ((nba.length == 257) && (nba[0] != 0))) {
                String errorMessage = "Modulus of RSA public key has wrong size.";
                throw new IllegalStateException(errorMessage);
            }
            if (nba.length == 257) {
                System.arraycopy(nba, 1, publicKeyEncoded, 0, 256);
            } else {
                System.arraycopy(nba, 0, publicKeyEncoded, 0, 256);
            }
            System.arraycopy(eba, 0, publicKeyEncoded, 256, eba.length);

            return publicKeyEncoded;
        }
        return null;
    }

    public static void main(String[] args) throws Exception {
        String s1 = "MIICVzCCAf2gAwIBAgIBATAKBggqhkjOPQQDAjAbMRkwFwYDVQQFExBjOGExZmM0MmUwNjQ5NDE4\nMCAXDTcwMDEwMTAwMDAwMFoYDzIxMDYwMjA3MDYyODE1WjAfMR0wGwYDVQQDDBRBbmRyb2lkIEtl\neXN0b3JlIEtleTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD5xc\\/5I4JVGgqwJ2WV4v2o97x\\/V\nw0yTRfdh0UnaSDbTxvKN1WWfZSxqbNPfTC8NnebaMW75f2VGTvXsdgHd6jCjggEqMIIBJjAOBgNV\nHQ8BAf8EBAMCB4AwggESBgorBgEEAdZ5AgERBIIBAjCB\\/wIBAgoBAQIBAwoBAQQgB4xqdP8okT9c\n7BLc44xby1l5dyAOXzkEozxMnoeIlgAEADBZv4U9CAIGAWtOz3Q4v4VFSQRHMEUxHzAdBBhjb20u\nbG9uZ2ouYW5kcm9pZC5samJhbmsCAUUxIgQgb36ULii95QG5ZJh6Swx\\/oaRgwHDKL0wiRkQX5Zny\nL58wcqEFMQMCAQKiAwIBA6MEAgIBAKUFMQMCAQSqAwIBAb+DeAMCAQK\\/hT4DAgEAv4U\\/AgUAv4VA\nKjAoBCDfwpIMgeE2\\/dKlEEeP2hN7Ji3FHUSe3X0L21VHRXJc\\/gEB\\/woBAL+FQQUCAwFfkL+FQgUC\nAwMUsDAKBggqhkjOPQQDAgNIADBFAiBgEUaJoA7dPVT6Ph0H4+8TKK7kJHCSa6dprF6zCytdnQIh\nAIrlx6LLEH8YonoryQ+1p4oGyxdaU3c\\/62k3U2IO\\/Zhl\n";

        String s2 ="MIIFYDCCA0igAwIBAgIJAOj6GWMU0voYMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNVBAUTEGY5MjAw\nOWU4NTNiNmIwNDUwHhcNMTYwNTI2MTYyODUyWhcNMjYwNTI0MTYyODUyWjAbMRkwFwYDVQQFExBm\nOTIwMDllODUzYjZiMDQ1MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAr7bHgiuxpwHs\nK7Qui8xUFmOr75gvMsd\\/dTEDDJdSSxtf6An7xyqpRR90PL2abxM1dEqlXnf2tqw1Ne4Xwl5jlRfd\nnJLmN0pTy\\/4lj4\\/7tv0Sk3iiKkypnEUtR6WfMgH0QZfKHM1+di+y9TFRtv6y\\/\\/0rb+T+W8a9nsNL\n\\/ggjnar86461qO0rOs2cXjp3kOG1FEJ5MVmFmBGtnrKpa73XpXyTqRxB\\/M0n1n\\/W9nGqC4FSYa04\nT6N5RIZGBN2z2MT5IKGbFlbC8UrW0DxW7AYImQQcHtGl\\/m00QLVWutHQoVJYnFPlXTcHYvASLu+R\nhhsbDmxMgJJ0mcDpvsC4PjvB+TxywElgS70vE0XmLD+OJtvsBslHZvPBKCOdT0MS+tgSOIfga+z1\nZ1g7+DVagf7quvmag8jfPioyKvxnK\\/EgsTUVi2ghzq8wm27ud\\/mIM7AY2qEORR8Go3TVB4HzWQgp\nZrt3i5MIlCaY504LzSRiigHCzAPlHws+W0rB5N+er5\\/2pJKnfBSDiCiFAVtCLOZ7gLiMm0jhO2B6\ntUXHI\\/+MRPjy02i59lINMRRev56GKtcd9qO\\/0kUJWdZTdA2XoS82ixPvZtXQpUpuL12ab+9EaDK8\nZ4RHJYYfCT3Q5vNAXaiWQ+8PTWm2QgBR\\/bkwSWc+NpUFgNPN9PvQi8WEg5UmAGMCAwEAAaOBpjCB\nozAdBgNVHQ4EFgQUNmHhAHyIBQlRi0RsR\\/8aTMnqTxIwHwYDVR0jBBgwFoAUNmHhAHyIBQlRi0Rs\nR\\/8aTMnqTxIwDwYDVR0TAQH\\/BAUwAwEB\\/zAOBgNVHQ8BAf8EBAMCAYYwQAYDVR0fBDkwNzA1oDOg\nMYYvaHR0cHM6Ly9hbmRyb2lkLmdvb2dsZWFwaXMuY29tL2F0dGVzdGF0aW9uL2NybC8wDQYJKoZI\nhvcNAQELBQADggIBACDIw41L3KlXG0aMiS\\/\\/cqrG+EShHUGo8HNsw30W1kJtjn6UBwRM6jnmiwfB\nPb8VA91chb2vssAtX2zbTvqBJ9+LBPGCdw\\/E53Rbf86qhxKaiAHOjpvAy5Y3m00mqC0w\\/Zwvju1t\nwb4vhLaJ5NkUJYsUS7rmJKHHBnETLi8GFqiEsqTWpG\\/6ibYCv7rYDBJDcR9W62BW9jfIoBQcxUCU\nJouMPH25lLNcDc1ssqvC2v7iUgI9LeoM1sNovqPmQUiG9rHli1vXxzCyaMTjwftkJLkf6724DFhu\nKug2jITV0QkXvaJWF4nUaHOTNA4uJU9WDvZLI1j83A+\\/xnAJUucIv\\/zGJ1AMH2boHqF8CY16LpsY\ngBt6tKxxWH00XcyDCdW2KlBCeqbQPcsFmWyWugxdcekhYsAWyoSf818NUsZdBWBaR\\/OukXrNLfkQ\n79IyZohZbvabO\\/X+MVT3rriAoKc8oE2Uws6DF+60PV7\\/WIPjNvXySdqspImSN78mflxDqwLqRBYk\nA3I75qppLGG9rp7UCdRjxMl8ZDBld+7yvHVgt1cVzJx9xnyGCC23UaicMDSXYrB4I4WHXPGjxhZu\nCuPBLTdOLU8YRvMYdEvYebWHMpvwGCF6bAx3JBpIeOQ1wDB5y0USicV3YgYGmi+NZfhA4URSh77Y\nd6uuJOJENRaNVTzk";

        String s3 = "MIIFYDCCA0igAwIBAgIJAOj6GWMU0voYMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNVBAUTEGY5MjAw\nOWU4NTNiNmIwNDUwHhcNMTYwNTI2MTYyODUyWhcNMjYwNTI0MTYyODUyWjAbMRkwFwYDVQQFExBm\nOTIwMDllODUzYjZiMDQ1MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAr7bHgiuxpwHs\nK7Qui8xUFmOr75gvMsd\\/dTEDDJdSSxtf6An7xyqpRR90PL2abxM1dEqlXnf2tqw1Ne4Xwl5jlRfd\nnJLmN0pTy\\/4lj4\\/7tv0Sk3iiKkypnEUtR6WfMgH0QZfKHM1+di+y9TFRtv6y\\/\\/0rb+T+W8a9nsNL\n\\/ggjnar86461qO0rOs2cXjp3kOG1FEJ5MVmFmBGtnrKpa73XpXyTqRxB\\/M0n1n\\/W9nGqC4FSYa04\nT6N5RIZGBN2z2MT5IKGbFlbC8UrW0DxW7AYImQQcHtGl\\/m00QLVWutHQoVJYnFPlXTcHYvASLu+R\nhhsbDmxMgJJ0mcDpvsC4PjvB+TxywElgS70vE0XmLD+OJtvsBslHZvPBKCOdT0MS+tgSOIfga+z1\nZ1g7+DVagf7quvmag8jfPioyKvxnK\\/EgsTUVi2ghzq8wm27ud\\/mIM7AY2qEORR8Go3TVB4HzWQgp\nZrt3i5MIlCaY504LzSRiigHCzAPlHws+W0rB5N+er5\\/2pJKnfBSDiCiFAVtCLOZ7gLiMm0jhO2B6\ntUXHI\\/+MRPjy02i59lINMRRev56GKtcd9qO\\/0kUJWdZTdA2XoS82ixPvZtXQpUpuL12ab+9EaDK8\nZ4RHJYYfCT3Q5vNAXaiWQ+8PTWm2QgBR\\/bkwSWc+NpUFgNPN9PvQi8WEg5UmAGMCAwEAAaOBpjCB\nozAdBgNVHQ4EFgQUNmHhAHyIBQlRi0RsR\\/8aTMnqTxIwHwYDVR0jBBgwFoAUNmHhAHyIBQlRi0Rs\nR\\/8aTMnqTxIwDwYDVR0TAQH\\/BAUwAwEB\\/zAOBgNVHQ8BAf8EBAMCAYYwQAYDVR0fBDkwNzA1oDOg\nMYYvaHR0cHM6Ly9hbmRyb2lkLmdvb2dsZWFwaXMuY29tL2F0dGVzdGF0aW9uL2NybC8wDQYJKoZI\nhvcNAQELBQADggIBACDIw41L3KlXG0aMiS\\/\\/cqrG+EShHUGo8HNsw30W1kJtjn6UBwRM6jnmiwfB\nPb8VA91chb2vssAtX2zbTvqBJ9+LBPGCdw\\/E53Rbf86qhxKaiAHOjpvAy5Y3m00mqC0w\\/Zwvju1t\nwb4vhLaJ5NkUJYsUS7rmJKHHBnETLi8GFqiEsqTWpG\\/6ibYCv7rYDBJDcR9W62BW9jfIoBQcxUCU\nJouMPH25lLNcDc1ssqvC2v7iUgI9LeoM1sNovqPmQUiG9rHli1vXxzCyaMTjwftkJLkf6724DFhu\nKug2jITV0QkXvaJWF4nUaHOTNA4uJU9WDvZLI1j83A+\\/xnAJUucIv\\/zGJ1AMH2boHqF8CY16LpsY\ngBt6tKxxWH00XcyDCdW2KlBCeqbQPcsFmWyWugxdcekhYsAWyoSf818NUsZdBWBaR\\/OukXrNLfkQ\n79IyZohZbvabO\\/X+MVT3rriAoKc8oE2Uws6DF+60PV7\\/WIPjNvXySdqspImSN78mflxDqwLqRBYk\nA3I75qppLGG9rp7UCdRjxMl8ZDBld+7yvHVgt1cVzJx9xnyGCC23UaicMDSXYrB4I4WHXPGjxhZu\nCuPBLTdOLU8YRvMYdEvYebWHMpvwGCF6bAx3JBpIeOQ1wDB5y0USicV3YgYGmi+NZfhA4URSh77Y\nd6uuJOJENRaNVTzk\n";
        String s4 = "MIICWDCCAf2gAwIBAgIBATAKBggqhkjOPQQDAjAbMRkwFwYDVQQFExBjOGExZmM0MmUwNjQ5NDE4MCAXDTcwMDEwMTAwMDAwMFoYDzIxMDYwMjA3MDYyODE1WjAfMR0wGwYDVQQDDBRBbmRyb2lkIEtleXN0b3JlIEtleTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABKHCoWHEE4 O2wqWzVQcuVLe9Q4AgFUZWVk5agTZL7D1GaiwbZnUq5ti44z0GNViL2P3aRRRgu1Fs7sjxtde3RSjggEqMIIBJjAOBgNVHQ8BAf8EBAMCB4AwggESBgorBgEEAdZ5AgERBIIBAjCB/wIBAgoBAQIBAwoBAQQgSVqJ4d9aIsU8aKL3fsVFvNY265VMFHoe2W9hnAObiXgEADBZv4U9CAIGAWtP1xSAv4VFSQRHMEUxHzAdBBhjb20ubG9uZ2ouYW5kcm9pZC5samJhbmsCAUUxIgQgb36ULii95QG5ZJh6Swx/oaRgwHDKL0wiRkQX5ZnyL58wcqEFMQMCAQKiAwIBA6MEAgIBAKUFMQMCAQSqAwIBAb DeAMCAQK/hT4DAgEAv4U/AgUAv4VAKjAoBCDfwpIMgeE2/dKlEEeP2hN7Ji3FHUSe3X0L21VHRXJc/gEB/woBAL FQQUCAwFfkL FQgUCAwMUsDAKBggqhkjOPQQDAgNJADBGAiEA7dT8dwb3KPXIHeJ2iIan7pS/fBysZwRHRq5 3W1Jmg8CIQC7BiZrJ TQJEtxkgJfaYwgzTcoWbcbPvpOKoflm2 /cQ==";
        //        JsonParser parser = new JsonParser();
//        JsonArray RespJarray = parser.parse(s1).getAsJsonArray();
//        java.security.cert.Certificate AndroidKeyRespCert;
//        List<X509Certificate> RespcertList = new ArrayList<X509Certificate>();
//        for (int i = 0; i < RespJarray.size(); i++) {
//            String certstr = RespJarray.get(i).getAsString();
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            X509Certificate cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(Convert.fromBase64(s4)));
            KeyDescription description = parseCert(cert);
            AuthorizationList list = description.getTeeEnforced();
            System.out.println("userAuthType:" + list.getUserAuthType());
        //}


    }
}
